{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#                                计算机视觉的应用"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 概述\n",
    "\n",
    "计算机视觉是当前深度学习研究最广泛、落地最成熟的技术领域，在手机拍照、智能安防、自动驾驶等场景有广泛应用。从2012年AlexNet在ImageNet比赛夺冠以来，深度学习深刻推动了计算机视觉领域的发展，当前最先进的计算机视觉算法几乎都是深度学习相关的。深度神经网络可以逐层提取图像特征，并保持局部不变性，被广泛应用于分类、检测、分割、跟踪、检索、识别、提升、重建等视觉任务中。\n",
    "本次体验结合图像分类任务，介绍MindSpore如何应用于计算机视觉场景，如何训练模型，得出一个性能较优的模型。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 图像分类\n",
    "\n",
    "图像分类是最基础的计算机视觉应用，属于有监督学习类别。给定一张数字图像，判断图像所属的类别，如猫、狗、飞机、汽车等等。用函数来表示这个过程如下："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "def classify(image):\n",
    "   label = model(image)\n",
    "   return label\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "定义的分类函数，以图片数据`image`为输入，通过`model`方法对`image`进行分类，最后返回分类结果。选择合适的`model`是关键。这里的`model`一般指的是深度卷积神经网络，如AlexNet、VGG、GoogLeNet、ResNet等等。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "下面按照MindSpore的训练数据模型的正常步骤进行，当使用到MindSpore或者图像分类操作时，会增加相应的说明，本次体验的整体流程如下："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. 数据集的准备，这里使用的是CIFAR-10数据集。\n",
    "\n",
    "2. 构建一个卷积神经网络，这里使用ResNet-50网络。\n",
    "\n",
    "3. 定义损失函数和优化器。\n",
    "\n",
    "4. 调用Model高阶API进行训练和保存模型文件。\n",
    "\n",
    "5. 加载保存的模型进行验证。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "本次面向Ascend 910 AI处理器硬件平台,将卷积神经网络ResNet加入到案例中，你可以在这里下载完整的样例代码案例作为基础用例：\n",
    "https://gitee.com/mindspore/docs/tree/master/tutorials/tutorial_code/resnet"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 训练数据集下载\n",
    "\n",
    "### 数据集准备"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 方法一：\n",
    "\n",
    "数据集可以从CIFAR-10数据集的官网进行下载：https://www.cs.toronto.edu/~kriz/cifar.html\n",
    "将数据集的解压缩文件夹`cifar-10-binary`放在Jupyter工作目录下。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 方法二:\n",
    "\n",
    "linux环境下用如下的命令 `wget https://www.cs.toronto.edu/~kriz/cifar-10-binary.tar.gz`。\n",
    "接下来需要解压数据集，解压命令如下：`tar -zvxf cifar-10-binary.tar.gz`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 数据处理\n",
    "\n",
    "数据集处理对于训练非常重要，好的数据集可以有效提高训练精度和效率。在加载数据集前，我们通常会对数据集进行一些处理。这里我们用到了数据增强，数据混洗和批处理。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "导入`argparse`模块，将9个参数传入`args_opt`变量包括："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `run_distribute`：控制是否进行初始化。\n",
    "- `device_num`：设置使用device的个数。\n",
    "- `do_train`：设置是否进行训练。\n",
    "- `do_eval`：设置是否计算最后的误差结果。\n",
    "- `epoch_size`：设置迭代次数。\n",
    "- `batch_size`：设置批次大小。\n",
    "- `num_classes`：设置分成多少个类。\n",
    "- `checkpoint_path`：设置CheckPoint文件路径。\n",
    "- `dataset_path`：数据集的路径。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import random\n",
    "import argparse\n",
    "from mindspore import Tensor\n",
    "from mindspore.ops import operations as P\n",
    "\n",
    "# Set Training Parameters \n",
    "random.seed(1)\n",
    "parser = argparse.ArgumentParser(description='Image classification')\n",
    "parser.add_argument('--run_distribute', type=bool, default=False, help='Run distribute.')\n",
    "# Set device number\n",
    "parser.add_argument('--device_num', type=int, default=1, help='Device num.')\n",
    "# Set whether do train\n",
    "parser.add_argument('--do_train', type=bool, default=True, help='Do train or not.')\n",
    "# Set whether do eval\n",
    "parser.add_argument('--do_eval', type=bool, default=True, help='Do eval or not.')\n",
    "# Set epoch size which is used to adjust model performance.\n",
    "parser.add_argument('--epoch_size', type=int, default=10, help='Epoch size.')\n",
    "parser.add_argument('--batch_size' type=int, default=32, help='Batch size.')\n",
    "# Set class number\n",
    "parser.add_argument('--num_classes', type=int, default=10, help='Num classes.')\n",
    "parser.add_argument('--checkpoint_path', type=str, default=None, help='CheckPoint file path.')\n",
    "parser.add_argument('--dataset_path', type=str, default=None, help='Dataset path.')\n",
    "args_opt = parser.parse_known_args()[0]\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "设置设备ID和数据集的路径，并设置处理器为Ascend。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from mindspore import context\n",
    "\n",
    "# Set the device for run code\n",
    "device_id = 0\n",
    "# Set the data set path\n",
    "data_home = './cifar-10-batches-bin'\n",
    "context.set_context(mode=context.GRAPH_MODE, device_target=\"Ascend\")\n",
    "context.set_context(device_id=device_id)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "数据增强主要是对数据进行归一化和丰富数据样本数量。常见的数据增强方式包括裁剪、翻转、色彩变化等等。MindSpore通过调用`map`方法在图片上执行增强操作。数据混洗和批处理主要是通过数据混洗`shuffle`随机打乱数据的顺序，并按`batch`读取数据，进行模型训练。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "构建`create_dataset`函数，来创建数据集。通过设置` resize_height`、`resize_width`、`rescale`、`shift`参数，定义`map`以及在图片上运用`map`实现数据增强。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import mindspore.nn as nn\n",
    "import mindspore.common.dtype as mstype\n",
    "import mindspore.ops.functional as F\n",
    "import mindspore.dataset as ds\n",
    "import mindspore.dataset.transforms.vision.c_transforms as C\n",
    "import mindspore.dataset.transforms.c_transforms as C2\n",
    "\n",
    "\n",
    "def create_dataset(repeat_num=1, training=True):\n",
    "    \"\"\"\n",
    "    create data for next use such as training or infering\n",
    "    \"\"\"\n",
    "    cifar_ds = ds.Cifar10Dataset(data_home)\n",
    "\n",
    "    if args_opt.run_distribute:\n",
    "        rank_id = int(os.getenv('RANK_ID'))\n",
    "        rank_size = int(os.getenv('RANK_SIZE'))\n",
    "        cifar_ds = ds.Cifar10Dataset(data_home, num_shards=rank_size, shard_id=rank_id)\n",
    "\n",
    "    # Data enhancement \n",
    "    resize_height = 224\n",
    "    resize_width = 224\n",
    "    rescale = 1.0 / 255.0\n",
    "    shift = 0.0\n",
    " \n",
    "    # Define map operations\n",
    "    # Padding_mode default CONSTANT\n",
    "    random_crop_op = C.RandomCrop((32, 32), (4, 4, 4, 4)) \n",
    "    random_horizontal_op = C.RandomHorizontalFlip()\n",
    "    # Interpolation default BILINEAR\n",
    "    resize_op = C.Resize((resize_height, resize_width))\n",
    "    rescale_op = C.Rescale(rescale, shift)\n",
    "    normalize_op = C.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))\n",
    "    changeswap_op = C.HWC2CHW()\n",
    "    type_cast_op = C2.TypeCast(mstype.int32)\n",
    "\n",
    "    c_trans = []\n",
    "    if training:\n",
    "        c_trans = [random_crop_op, random_horizontal_op]\n",
    "    c_trans += [resize_op, rescale_op, normalize_op,\n",
    "                changeswap_op]\n",
    "\n",
    "    # Apply map operations on images\n",
    "    cifar_ds = cifar_ds.map(input_columns=\"label\", operations=type_cast_op)\n",
    "    cifar_ds = cifar_ds.map(input_columns=\"image\", operations=c_trans)\n",
    "\n",
    "    # Apply shuffle operations\n",
    "    cifar_ds = cifar_ds.shuffle(buffer_size=10)\n",
    "\n",
    "    # Apply batch operations\n",
    "    cifar_ds = cifar_ds.batch(batch_size=args_opt.batch_size, drop_remainder=True)\n",
    "\n",
    "    # Apply repeat operations\n",
    "    cifar_ds = cifar_ds.repeat(repeat_num)\n",
    "\n",
    "    return cifar_ds"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "数据集生成后，我们可以通过`imshow`方法对数据集`cifar_ds`进行可视化。这里可以得到CIFAR-10数据集中的一张图片。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x7f8299206e90>"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "dataset_show = create_dataset()\n",
    "iterator_show= dataset_show.create_dict_iterator()\n",
    "images = iterator_show.get_next()[\"image\"]\n",
    "# Images[0].shape is (3,224,224).We need transpose as (224,224,3) for using in plt.show().\n",
    "picture_show = np.transpose(images[0],(1,2,0))\n",
    "plt.imshow(picture_show)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 定义卷积神经网络\n",
    "\n",
    "卷积神经网络已经是图像分类任务的标准算法了。卷积神经网络采用分层的结构对图片进行特征提取，由一系列的网络层堆叠而成，比如卷积层、池化层、激活层等等。\n",
    "ResNet-50通常是较好的选择。首先，它足够深，常见的有34层，50层，101层。通常层次越深，表征能力越强，分类准确率越高。其次，可学习，采用了残差结构，通过shortcut连接把低层直接跟高层相连，解决了反向传播过程中因为网络太深造成的梯度消失问题。此外，ResNet-50网络的性能很好，既表现为识别的准确率，也包括它本身模型的大小和参数量。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在构建ResNet-50网络中，初始化参数，通过判断`args`的参数，用户决定用哪些功能。\n",
    "可以通过改变`epoch_size`来调节模型，获得更好的性能。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "from mindspore.communication.management import init\n",
    "from mindspore.train.model import Model\n",
    "from mindspore.context import ParallelMode\n",
    "from resnet import resnet50\n",
    "from mindspore.parallel._auto_parallel_context import auto_parallel_context\n",
    "\n",
    "# In this way by judging the mark of args, users will decide which function to use\n",
    "if not args_opt.do_eval and args_opt.run_distribute:\n",
    "    context.set_auto_parallel_context(device_num=args_opt.device_num, parallel_mode=ParallelMode.DATA_PARALLEL)\n",
    "    auto_parallel_context().set_all_reduce_fusion_split_indices([140])\n",
    "    init()\n",
    "epoch_size = args_opt.epoch_size\n",
    "net = resnet50(args_opt.batch_size, args_opt.num_classes)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 定义损失函数和优化器\n",
    "\n",
    "接下来需要定义损失函数（Loss）和优化器（Optimizer）。损失函数是深度学习的训练目标，也叫目标函数，可以理解为神经网络的输出（Logits）和标签(Labels)之间的距离，是一个标量数据。\n",
    "常见的损失函数包括均方误差、L2损失、Hinge损失、交叉熵等等。图像分类应用通常采用交叉熵损失（CrossEntropy）。\n",
    "优化器用于神经网络求解（训练）。由于神经网络参数规模庞大，无法直接求解，因而深度学习中采用随机梯度下降算法（SGD）及其改进算法进行求解。MindSpore封装了常见的优化器，如SGD、ADAM、Momemtum等等。本例采用Momentum优化器，通常需要设定两个参数，动量（moment）和权重衰减项（weight decay）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "通过调用MindSpore中的API：`Momentum`和`SoftmaxCrossEntropyWithLogits`，设置损失函数和优化器的参数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "from mindspore.nn.optim.momentum import Momentum\n",
    "from mindspore.nn.loss import SoftmaxCrossEntropyWithLogits\n",
    "\n",
    "ls = SoftmaxCrossEntropyWithLogits(sparse=True, reduction=\"mean\")\n",
    "opt = Momentum(filter(lambda x: x.requires_grad, net.get_parameters()), 0.01, 0.9)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 调用Model高阶API进行训练和保存模型文件\n",
    "\n",
    "完成数据预处理、网络定义、损失函数和优化器定义之后，就可以进行模型训练了。模型训练包含两层迭代，数据集的多轮迭代（epoch）和一轮数据集内按分组（batch）大小进行的单步迭代。其中，单步迭代指的是按分组从数据集中抽取数据，输入到网络中计算得到损失函数，然后通过优化器计算和更新训练参数的梯度。\n",
    "\n",
    "为了简化训练过程，MindSpore封装了Model高阶接口。用户输入网络、损失函数和优化器完成Model的初始化，然后调用`train`接口进行训练，`train`接口参数包括迭代次数`epoch`和数据集`dataset`。\n",
    "\n",
    "模型保存是对训练参数进行持久化的过程。`Model`类中通过回调函数的方式进行模型保存，如下面代码所示。用户通过`CheckpointConfig`设置回调函数的参数，其中，`save_checkpoint_steps`指每经过固定的单步迭代次数保存一次模型，`keep_checkpoint_max`指最多保存的模型个数。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "本次体验选择`epoch_size`为10，一共迭代了十次，得到如下的运行结果。体验者可以自行设置不同的`epoch_size`，生成不同的模型，在下面的验证部分查看模型精确度。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:00:19.338.911 [mindspore/train/serialization.py:320] Execute save the graph process.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:00:26.722.576 [mindspore/train/callback/_callback.py:52] update parameters in the net.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:00:26.857.220 [mindspore/train/serialization.py:262] Execute load parameter into net process.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:00:26.901.030 [mindspore/train/serialization.py:284] Load parameter into net finish, 0 parameters has not been loaded.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:00:26.905.358 [mindspore/train/serialization.py:138] Execute save checkpoint process.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:00:27.502.16 [mindspore/train/serialization.py:164] Save checkpoint process finish.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch: 1 step: 1875, loss is 1.2926\n",
      "Epoch time: 105040.679, per step time: 56.022, avg loss: 1.293\n",
      "************************************************************\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:01:25.345.641 [mindspore/train/callback/_callback.py:52] update parameters in the net.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:01:25.410.278 [mindspore/train/serialization.py:262] Execute load parameter into net process.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:01:25.453.675 [mindspore/train/serialization.py:284] Load parameter into net finish, 0 parameters has not been loaded.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:01:25.457.693 [mindspore/train/serialization.py:138] Execute save checkpoint process.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:01:25.650.828 [mindspore/train/serialization.py:164] Save checkpoint process finish.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch: 2 step: 1875, loss is 0.8226\n",
      "Epoch time: 58600.447, per step time: 31.254, avg loss: 0.823\n",
      "************************************************************\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:02:23.950.189 [mindspore/train/callback/_callback.py:52] update parameters in the net.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:02:24.153.21 [mindspore/train/serialization.py:262] Execute load parameter into net process.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:02:24.591.32 [mindspore/train/serialization.py:284] Load parameter into net finish, 0 parameters has not been loaded.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:02:24.632.58 [mindspore/train/serialization.py:138] Execute save checkpoint process.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:02:24.255.873 [mindspore/train/serialization.py:164] Save checkpoint process finish.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch: 3 step: 1875, loss is 0.6473\n",
      "Epoch time: 58604.997, per step time: 31.256, avg loss: 0.647\n",
      "************************************************************\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:03:22.548.058 [mindspore/train/callback/_callback.py:52] update parameters in the net.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:03:22.613.155 [mindspore/train/serialization.py:262] Execute load parameter into net process.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:03:22.664.126 [mindspore/train/serialization.py:284] Load parameter into net finish, 0 parameters has not been loaded.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:03:22.668.172 [mindspore/train/serialization.py:138] Execute save checkpoint process.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:03:22.858.740 [mindspore/train/serialization.py:164] Save checkpoint process finish.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch: 4 step: 1875, loss is 0.3235\n",
      "Epoch time: 58602.803, per step time: 31.255, avg loss: 0.324\n",
      "************************************************************\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:04:21.151.561 [mindspore/train/callback/_callback.py:52] update parameters in the net.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:04:21.215.250 [mindspore/train/serialization.py:262] Execute load parameter into net process.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:04:21.257.986 [mindspore/train/serialization.py:284] Load parameter into net finish, 0 parameters has not been loaded.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:04:21.261.961 [mindspore/train/serialization.py:138] Execute save checkpoint process.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:04:21.453.475 [mindspore/train/serialization.py:164] Save checkpoint process finish.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch: 5 step: 1875, loss is 0.4524\n",
      "Epoch time: 58594.759, per step time: 31.251, avg loss: 0.452\n",
      "************************************************************\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:05:19.749.137 [mindspore/train/callback/_callback.py:52] update parameters in the net.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:05:19.813.864 [mindspore/train/serialization.py:262] Execute load parameter into net process.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:05:19.857.466 [mindspore/train/serialization.py:284] Load parameter into net finish, 0 parameters has not been loaded.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:05:19.861.498 [mindspore/train/serialization.py:138] Execute save checkpoint process.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:05:20.542.51 [mindspore/train/serialization.py:164] Save checkpoint process finish.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch: 6 step: 1875, loss is 0.5436\n",
      "Epoch time: 58600.685, per step time: 31.254, avg loss: 0.544\n",
      "************************************************************\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:06:18.348.434 [mindspore/train/callback/_callback.py:52] update parameters in the net.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:06:18.412.409 [mindspore/train/serialization.py:262] Execute load parameter into net process.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:06:18.455.244 [mindspore/train/serialization.py:284] Load parameter into net finish, 0 parameters has not been loaded.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:06:18.459.279 [mindspore/train/serialization.py:138] Execute save checkpoint process.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:06:18.653.804 [mindspore/train/serialization.py:164] Save checkpoint process finish.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch: 7 step: 1875, loss is 0.3080\n",
      "Epoch time: 58599.470, per step time: 31.253, avg loss: 0.308\n",
      "************************************************************\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:07:16.948.524 [mindspore/train/callback/_callback.py:52] update parameters in the net.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:07:17.128.67 [mindspore/train/serialization.py:262] Execute load parameter into net process.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:07:17.584.99 [mindspore/train/serialization.py:284] Load parameter into net finish, 0 parameters has not been loaded.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:07:17.625.36 [mindspore/train/serialization.py:138] Execute save checkpoint process.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:07:17.254.278 [mindspore/train/serialization.py:164] Save checkpoint process finish.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch: 8 step: 1875, loss is 0.4420\n",
      "Epoch time: 58600.389, per step time: 31.254, avg loss: 0.442\n",
      "************************************************************\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:08:15.546.176 [mindspore/train/callback/_callback.py:52] update parameters in the net.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:08:15.611.947 [mindspore/train/serialization.py:262] Execute load parameter into net process.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:08:15.655.998 [mindspore/train/serialization.py:284] Load parameter into net finish, 0 parameters has not been loaded.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:08:15.660.156 [mindspore/train/serialization.py:138] Execute save checkpoint process.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:08:15.853.579 [mindspore/train/serialization.py:164] Save checkpoint process finish.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch: 9 step: 1875, loss is 0.2113\n",
      "Epoch time: 58599.249, per step time: 31.253, avg loss: 0.211\n",
      "************************************************************\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:09:14.147.518 [mindspore/train/callback/_callback.py:52] update parameters in the net.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:09:14.211.164 [mindspore/train/serialization.py:262] Execute load parameter into net process.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:09:14.257.088 [mindspore/train/serialization.py:284] Load parameter into net finish, 0 parameters has not been loaded.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:09:14.261.142 [mindspore/train/serialization.py:138] Execute save checkpoint process.\n",
      "[INFO] ME(27502:140200539502400,MainProcess):2020-07-18-00:09:14.437.118 [mindspore/train/serialization.py:164] Save checkpoint process finish.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch: 10 step: 1875, loss is 0.3720\n",
      "Epoch time: 58583.483, per step time: 31.245, avg loss: 0.372\n",
      "************************************************************\n"
     ]
    }
   ],
   "source": [
    "from mindspore.train.callback import ModelCheckpoint, CheckpointConfig, LossMonitor\n",
    "from mindspore.train.serialization import load_checkpoint, load_param_into_net\n",
    "\n",
    "model = Model(net, loss_fn=ls, optimizer=opt, metrics={'acc'})\n",
    "\n",
    "# As for train, users could use model.train\n",
    "if args_opt.do_train:\n",
    "    dataset = create_dataset(epoch_size)\n",
    "    batch_num = dataset.get_dataset_size()\n",
    "    config_ck = CheckpointConfig(save_checkpoint_steps=batch_num, keep_checkpoint_max=35)\n",
    "    ckpoint_cb = ModelCheckpoint(prefix=\"train_resnet_cifar10\", directory=\"./\", config=config_ck)\n",
    "    loss_cb = LossMonitor()\n",
    "    model.train(epoch_size, dataset, callbacks=[ckpoint_cb, loss_cb])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 加载保存的模型进行验证\n",
    "\n",
    "使用保存的模型，调用`model.eval`得到最终精度数据约为0.84远高于0.5，准确度较高，验证得出模型是性能较优的。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "result:  {'acc': 0.8386833333333333}\n"
     ]
    }
   ],
   "source": [
    "# As for evaluation, users could use model.eval\n",
    "if args_opt.do_eval:\n",
    "    if args_opt.checkpoint_path:\n",
    "        param_dict = load_checkpoint(args_opt.checkpoint_path)\n",
    "        load_param_into_net(net, param_dict)\n",
    "    eval_dataset = create_dataset(1, training=False)\n",
    "    res = model.eval(eval_dataset)\n",
    "    print(\"result: \", res)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 总结\n",
    "\n",
    "本次体验，带领体验者了解了MindSpore的卷积神经网络ResNet-50，通过构建ResNet-50对CIFAR-10进行分类。可以看出MindSpore的ResNet-50的构建非常容易，损失函数和优化器都有封装好的API，对于初学者和研发人员都非常的友善。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
